[PATCH 14/24] imap-login: Limit the number of open IMAP parser lists
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Fri, 6 Mar 2026 13:35:12 +0000 (15:35 +0200)
committerNoah Meyerhans <noahm@debian.org>
Tue, 31 Mar 2026 19:07:17 +0000 (15:07 -0400)
This prevents attackers from using a large number of '(' in a command to
grow memory usage excessively.

Gbp-Pq: Name CVE-2026-27857-4.patch

src/imap-login/imap-login-client.c
src/imap-login/imap-login-client.h
src/imap-login/imap-login-cmd-id.c

index f24b90e05200d684ac868898094e7e00678c5ee5..23c4a2f8eebadd8857c8c3d81dfe9c06c6260714 100644 (file)
@@ -379,10 +379,13 @@ static int imap_client_create(struct client *client)
                return -1;
        }
 
+       struct imap_parser_params params = {
+               .list_count_limit = IMAP_LOGIN_LIST_COUNT_LIMIT,
+       };
        imap_client->parser =
                imap_parser_create(imap_client->common.input,
                                   imap_client->common.output,
-                                  IMAP_LOGIN_MAX_LINE_LENGTH, NULL);
+                                  IMAP_LOGIN_MAX_LINE_LENGTH, &params);
        struct settings_instance *set_instance = settings_instance_find(client->event);
        if (set_instance == NULL) {
                set_instance = settings_instance_new(
@@ -464,11 +467,14 @@ static void imap_client_starttls(struct client *client)
        struct imap_client *imap_client =
                container_of(client, struct imap_client, common);
 
+       struct imap_parser_params params = {
+               .list_count_limit = IMAP_LOGIN_LIST_COUNT_LIMIT,
+       };
        imap_parser_unref(&imap_client->parser);
        imap_client->parser =
                imap_parser_create(imap_client->common.input,
                                   imap_client->common.output,
-                                  IMAP_LOGIN_MAX_LINE_LENGTH, NULL);
+                                  IMAP_LOGIN_MAX_LINE_LENGTH, &params);
 
        /* CRLF is lost from buffer when streams are reopened. */
        imap_client->skip_line = FALSE;
index a62d30445a2a5f7bcdd1aadc7fc55041a72e9057..34ea226c707c4b67e30830b3db07133fc58bd32b 100644 (file)
 /* maximum length for IMAP command line. */
 #define IMAP_LOGIN_MAX_LINE_LENGTH 8192
 
+/* Maximum number of '(' allowed in an IMAP command. Pre-login only uses
+   lists in the ID command. */
+#define IMAP_LOGIN_LIST_COUNT_LIMIT 1
+
 enum imap_client_id_state {
        IMAP_CLIENT_ID_STATE_LIST = 0,
        IMAP_CLIENT_ID_STATE_KEY,
index 806486d47462aef597c06e4d41c7ead30ffecb68..a0bb9cdc03f7d691d5e229000c33eb32a1baa554 100644 (file)
@@ -344,10 +344,14 @@ int cmd_id(struct imap_client *client)
                client->cmd_id = id = i_new(struct imap_client_cmd_id, 1);
                id->params = p_new(param_pool, struct imap_id_params, 1);
                id->params->pool = param_pool;
+
+               struct imap_parser_params params = {
+                       .list_count_limit = IMAP_LOGIN_LIST_COUNT_LIMIT,
+               };
                id->parser = imap_parser_create(client->common.input,
                                                client->common.output,
                                                IMAP_LOGIN_MAX_LINE_LENGTH,
-                                               NULL);
+                                               &params);
                id->log_reply = str_new(default_pool, 64);
                if (client->set->imap_literal_minus)
                        imap_parser_enable_literal_minus(id->parser);